using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using CodeLibrary.NativeMethods.Native;
using CodeLibrary.NativeMethods.Utils;

namespace CodeLibrary.Diagnostics.Utils
{
    public static class ProcessUtils
    {
        public static string GetCommandLineOutput(
            string commandLine, out int exitCode,
            string exeFile = "", string workingDirectory = "",
            int milliseconds = 0)
        {
            exitCode = 0;
            var p = new Process();
            string res = string.Empty;
            if (exeFile == "")
            {
                p.StartInfo.FileName = "cmd.exe";
                p.StartInfo.Arguments = "/c " + commandLine;
            }
            else
            {
                p.StartInfo.FileName = exeFile;
                p.StartInfo.Arguments = commandLine;
            }
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardInput = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.CreateNoWindow = true;
            if (workingDirectory != "")
            {
                p.StartInfo.WorkingDirectory = workingDirectory;
            }
            try
            {
                if (p.Start())
                {
                    if (milliseconds == 0)
                    {
                        p.WaitForExit();
                    }
                    else
                    {
                        p.WaitForExit(milliseconds);
                    }
                    res = p.StandardOutput.ReadToEnd();
                    exitCode = p.ExitCode;
                    if (exitCode != 0)
                    {
                        res += "\n" + p.StandardError.ReadToEnd();
                    }
                }
            }
            finally
            {
                p.Close();
            }
            return res;
        }

        public static int GetParantPID(int APID)
        {
            IntPtr hProc = OpenProcess((ProcessAccessFlags)0x001F0FFF, false, APID);
            IntPtr pbi = Marshal.AllocHGlobal(
                Marshal.SizeOf(typeof(PROCESS_BASIC_INFORMATION)));
            IntPtr outLong = Marshal.AllocHGlobal(sizeof(long));
            NtdllUtils.NtQueryInformationProcess(
                hProc, 0, pbi,
                (uint)Marshal.SizeOf(typeof(PROCESS_BASIC_INFORMATION)), outLong);
            CloseHandle(hProc);
            Marshal.FreeHGlobal(outLong);
            Marshal.FreeHGlobal(pbi);
            return (int)((PROCESS_BASIC_INFORMATION)Marshal.PtrToStructure(
                pbi, typeof(PROCESS_BASIC_INFORMATION))).InheritedFromUniqueProcessId;
        }

        public static IntPtr OpenProcess(
            ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId)
        {
            return Kernel32Utils.OpenProcess(
                dwDesiredAccess, bInheritHandle, dwProcessId);
        }

        public static void CloseHandle(IntPtr hObject)
        {
            Kernel32Utils.CloseHandle(hObject);
        }
    }
}